/*
 * restserver - A smart, efficient, low consumption RESTful application service platform writen in C
 * author	: calvin
 * email	: calvinwilliams@163.com
 *
 * Licensed under the Apache License v2.0, see the file LICENSE in base directory.
 */

#include "in.h"

int ProcessHttpRequest( struct RestServerContext *ctx )
{
	int			nret = 0 ;
	
	nret = ParseHttpToRestServerContext( ctx ) ;
	if( nret < 0 )
	{
		FATALLOG( "ParseHttpToRestServerContext failed[%d]" , nret )
		exit(9);
	}
	else if( nret > 0 )
	{
		ERRORLOG( "ParseHttpToRestServerContext failed[%d]" , nret )
		return nret;
	}
	else
	{
		INFOLOG( "ParseHttpToRestServerContext ok" )
	}
	
	if( ctx->so_handle == NULL )
	{
		INFOLOG( "dlopen[%s] ..." , ctx->conf.server.application_so_pathfilename )
		ctx->so_handle = dlopen( ctx->conf.server.application_so_pathfilename , RTLD_NOW | RTLD_GLOBAL ) ;
		if( ctx->so_handle == NULL )
		{
			ERRORLOG( "dlopen[%s] failed , errno[%d] dlerror[%s]" , ctx->conf.server.application_so_pathfilename , errno , dlerror() )
			return HTTP_SERVICE_UNAVAILABLE;
		}
		else
		{
			INFOLOG( "dlopen[%s] ok" , ctx->conf.server.application_so_pathfilename )
		}
		
		ctx->pfuncInitRestApplication = (funcInitRestApplication *)dlsym( ctx->so_handle , "InitRestApplication" ) ;
		ctx->pfuncCallRestApplication = (funcCallRestApplication *)dlsym( ctx->so_handle , "CallRestApplication" ) ;
		ctx->pfuncCleanRestApplication = (funcCleanRestApplication *)dlsym( ctx->so_handle , "CleanRestApplication" ) ;
		if( ctx->pfuncInitRestApplication == NULL || ctx->pfuncCallRestApplication == NULL || ctx->pfuncCleanRestApplication == NULL )
		{
			ERRORLOG( "dlsym all funcptr failed" )
			goto RESET_SO_HANDLE_AND_FUNCSPTR;
		}
	}
	
	if( ctx->pfuncInitRestApplication )
	{
		INFOLOG( "call pfuncInitRestApplication ..." )
		nret = ctx->pfuncInitRestApplication( ctx ) ;
		if( nret < 0 )
		{
			FATALLOG( "call pfuncInitRestApplication failed[%d]" , nret )
			exit(9);
		}
		else if( nret > 0 )
		{
			ERRORLOG( "call pfuncInitRestApplication failed[%d]" , nret )
			goto RESET_SO_HANDLE_AND_FUNCSPTR;
		}
		else
		{
			INFOLOG( "call pfuncInitRestApplication ok" )
		}
		
		ctx->pfuncInitRestApplication = NULL ;
	}
	
	INFOLOG( "call pfuncCallRestApplication ..." )
	nret = ctx->pfuncCallRestApplication( ctx ) ;
	if( nret < 0 )
	{
		FATALLOG( "call pfuncCallRestApplication failed[%d]" , nret )
		exit(9);
	}
	else if( nret > 0 )
	{
		ERRORLOG( "call pfuncCallRestApplication failed[%d]" , nret )
		goto RESET_SO_HANDLE_AND_FUNCSPTR;
	}
	else
	{
		INFOLOG( "call pfuncCallRestApplication ok" )
	}
	
	if( ctx->conf.server.test_mode )
	{
		if( ctx->pfuncCleanRestApplication )
		{
			INFOLOG( "call pfuncCleanRestApplication ..." )
			nret = ctx->pfuncCleanRestApplication( ctx ) ;
			if( nret < 0 )
			{
				FATALLOG( "call pfuncCleanRestApplication failed[%d]" , nret )
				exit(9);
			}
			else if( nret > 0 )
			{
				ERRORLOG( "call pfuncCleanRestApplication failed[%d]" , nret )
				goto RESET_SO_HANDLE_AND_FUNCSPTR;
			}
			else
			{
				INFOLOG( "call pfuncCleanRestApplication ok" )
			}
			
			ctx->pfuncCleanRestApplication = NULL ;
		}
		
		INFOLOG( "dlclose[%s] ..." , ctx->conf.server.application_so_pathfilename )
		ctx->pfuncCallRestApplication = NULL ;
		INFOLOG( "dlclose[%s] done" , ctx->conf.server.application_so_pathfilename )
		dlclose( ctx->so_handle );
		ctx->so_handle = NULL ;
	}
	
	return 0;

RESET_SO_HANDLE_AND_FUNCSPTR :
	
	ctx->pfuncInitRestApplication = NULL ;
	ctx->pfuncCallRestApplication = NULL ;
	ctx->pfuncCleanRestApplication = NULL ;
	dlclose( ctx->so_handle );
	ctx->so_handle = NULL ;
	
	return 1;
}

